package com.ruoyi.system.util;

import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.system.domain.OldStock;
import com.ruoyi.system.domain.SectorDetail;
import com.ruoyi.system.domain.SectorSpot;
import com.ruoyi.system.domain.Stock;
import com.ruoyi.system.domain.Stocklist;
import com.ruoyi.system.service.IOldStockService;
import com.ruoyi.system.service.IScreenstockService;
import com.ruoyi.system.service.ISectorDetailService;
import com.ruoyi.system.service.ISectorSpotService;
import com.ruoyi.system.service.IStockService;
import com.ruoyi.system.service.IStocklistService;
import com.ruoyi.system.service.impl.StockServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;

@Component("stockTask")
public class StockTask {

    @Autowired
    private IStocklistService stocklistService;

    @Autowired
    private IOldStockService oldStockService;

    @Autowired
    ISectorSpotService sectorSpotService;

    @Autowired
    ISectorDetailService sectorDetailService;

    @Autowired
    IStockService stockService;

    @Autowired
    IScreenstockService screenstockService;

    @Autowired
    HtmlUtil htmlUtil;

    @Autowired
    RedisTemplate redisTemplate;

    public Stock getOneBySymbolAndDate(String symbol, String date) {
        Stock stock = new Stock();
        stock.setSymbol(symbol);
        stock.setDate(DateUtils.parseDate(date));
        return stockService.getOne(stock);
    }

    @Transactional
//    @Scheduled(cron = "0 */5 * * * ?")
    public void getStockListDataByHtml() {
        Date date = DateUtils.parseDate(DateUtils.datePath());
        boolean isStart = LocalDateTime.now().getHour() > 9;
        boolean isEnd = LocalDateTime.now().getHour() < 15;
        if (!DataUtil.getTradeDay() && !isStart && !isEnd) {
            return;
        }
        List<Stock> stockList = new CopyOnWriteArrayList<>();
        try {
            htmlUtil.work(null, stockList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        for (Stock stock : stockList) {
            stock.setDate(date);
            List<Stock> stocks = redisTemplate.opsForList().range(stock.getSymbol(), 0, -1);
            stocks = stocks.stream().filter(stock1 -> !stock1.getDate().equals(date)).collect(Collectors.toList());
            stocks.add(stock);
            stocks = stocks.stream().sorted(Comparator.comparing(Stock::getDate).reversed()).collect(Collectors.toList());
            redisTemplate.delete(stock.getSymbol());
            redisTemplate.opsForList().rightPushAll(stock.getSymbol(), stocks);
        }
    }

    @Transactional
    @Scheduled(cron = "0 38 18 * * ?")
    public void getStockListData() {
//        if (!DataUtil.getTradeDay()) {
//            return;
//        }
        String[] url = new String[]{"python", PathUtils.PATH + "stockList.py"};
        List<String> stocks = pythonUtil.executeCMD(url);
        for (String stock : stocks) {
            String[] split = stock.split(",");
            Stock stockEntity = new Stock(split[0], split[1], split[2], split[3], split[4], split[5], split[6], split[7], split[8], split[9], split[10], split[11], split[12]);
            if (!(stockEntity.getSymbol().contains("sh") || stockEntity.getSymbol().contains("sz"))) {
                continue;
            }
            Stock symbolAndDate = getOneBySymbolAndDate(split[0], DateUtils.getDate());
            if (symbolAndDate != null) {
                stockEntity.setId(symbolAndDate.getId());
                stockService.updateStock(stockEntity);
            } else {
                stockEntity.setDate(DateUtils.parseDate(DateUtils.datePath()));
                stockService.insertStock(stockEntity);
            }
            Stocklist stocklistEntity = new Stocklist(split[0], split[1], split[0].substring(2));
            Stocklist stocklist = new Stocklist();
            stocklist.setSymbol(split[0]);
            Stocklist symbol = stocklistService.getOne(stocklist);
            if (symbol == null) {
                stocklistService.insertStocklist(stocklistEntity);
            }
        }
        //更新板块信息
//            sectorSpotService.updateSectorSpot();

    }

    //交易日14.45找出符合的票
    @Transactional
//    @Scheduled(cron = "00 45 14 * * ?")
    public void getStockListDataStart() {
        if (!DataUtil.getTradeDay()) {
            return;
        }
        List<Stocklist> allStock = stocklistService.selectStocklistList(new Stocklist());
        String[] url = new String[]{"python", PathUtils.PATH + "stockList.py"};
        List<String> stocks = pythonUtil.executeCMD(url);
        for (String stock : stocks) {
            String[] split = stock.split(",");
            Stock stockEntity = new Stock(split[0], split[1], split[2], split[3], split[4], split[5], split[6], split[7], split[8], split[9], split[10], split[11], split[12]);
            if (!(stockEntity.getSymbol().contains("sh") || stockEntity.getSymbol().contains("sz"))) {
                continue;
            }
            stockEntity.setDate(DateUtils.parseDate(DateUtils.datePath()));
            List<Stock> stockList = StockServiceImpl.stocksMap.get(stockEntity.getSymbol());
            stockList.add(stockEntity);
        }

        //计算MA，上升通道，股价在5天均线附近
        List<Stocklist> stock = new ArrayList<>();
        for (Stocklist stocklistEntity : allStock) {
            List<Stock> list = StockServiceImpl.stocksMap.get(stocklistEntity.getSymbol()).stream().sorted(Comparator.comparing(Stock::getDate).reversed()).collect(Collectors.toList());
            List<BigDecimal> day5 = MAUtils.calculateMA(5, list);
            List<BigDecimal> day13 = MAUtils.calculateMA(13, list);
            List<BigDecimal> day21 = MAUtils.calculateMA(21, list);
            if (day5.size() > 0 && day13.size() > 0 && day21.size() > 5) {
                double v5 = day5.get(0).doubleValue();
                double v13 = day13.get(0).doubleValue();
                double v21 = day21.get(0).doubleValue();

                if (lineUp(day21, 5) && list.get(0).getTrade().doubleValue() > v5 * 0.99 && list.get(0).getTrade().doubleValue() < v5 * 1.01 && v13 > v5 && list.get(0).getTrade().doubleValue() > v21) {
                    stock.add(stocklistEntity);
                }
            }

        }
        System.out.println(stock);
        screenstockService.saveScreen(stock);

    }

    private boolean lineUp(List<BigDecimal> list, int size) {
        boolean up = true;
        for (int i = 0; i < size - 1; i++) {
            if (list.get(i).doubleValue() < list.get(i + 1).doubleValue()) {
                up = false;
            }
        }
        return up;
    }


    ConcurrentLinkedQueue<Map<String, List<String>>> allStockPreData = new ConcurrentLinkedQueue<>();

    /**
     * 获取全部历史数据
     */
    //    @Scheduled(cron = "00 02 21 * * ?")
    public void getStockHData2() {
        List<Stocklist> allStock = stocklistService.selectStocklistList(new Stocklist());
        Map<String, Stocklist> collect = allStock.stream().collect(Collectors.toMap(Stocklist::getSymbol, stocklistEntity -> stocklistEntity));
        new Thread(() -> saveDate(collect)).start();
        boolean b = false;
        for (Stocklist stocklistEntity : allStock) {
            if (!b) {
                String[] url = new String[]{"python", PathUtils.PATH + "stock_zh_a_daily.py", stocklistEntity.getSymbol()};
                List<String> stocks = pythonUtil.executeCMD(url);
                Map<String, List<String>> map = new HashMap<>();
                map.put(stocklistEntity.getSymbol(), stocks);
                allStockPreData.add(map);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public void saveDate(Map<String, Stocklist> collect) {
        while (true) {
            if (allStockPreData.size() > 0) {
                Map<String, List<String>> poll = allStockPreData.poll();
                List<String> stocks = new ArrayList<>();
                String symbol = "";

                for (Map.Entry<String, List<String>> stringListEntry : poll.entrySet()) {
                    stocks = stringListEntry.getValue();
                    symbol = stringListEntry.getKey();
                }
                Stocklist stocklistEntity = collect.get(symbol);
                List<Stock> newEntityList = new ArrayList<>();
                List<Stock> oldEntityList = stockService.selectStockList(new Stock(stocklistEntity.getSymbol()));
                Map<Date, String> map = oldEntityList.stream().collect(Collectors.toMap(Stock::getDate, Stock::getName));
                for (String stock : stocks) {
                    String[] split = stock.split(",");
                    Stock stockEntity = new Stock(DateUtils.parseDate(split[0].substring(0, 10)), stocklistEntity.getSymbol(), stocklistEntity.getName(), split[4], split[1], split[2], split[3], split[5], split[6], split[7]);
                    if (map.containsKey(stockEntity.getDate())) {
                        continue;
                    }
                    newEntityList.add(stockEntity);
                }
                newEntityList.stream()
                        .sorted(Comparator.comparing(Stock::getDate).reversed())
                        .limit(100).map(stock -> stockService.insertStock(stock)).collect(Collectors.toList());

                //保存历史数据
                newEntityList.stream().map(stockEntity -> {
                    OldStock oldStockEntity = new OldStock();
                    BeanUtils.copyProperties(stockEntity, oldStockEntity);
                    return oldStockEntity;
                }).map(oldStock -> oldStockService.insertOldStock(oldStock));
            }
        }
    }
}
